﻿package extremefx.ui {
	import extremefx.geom.Size;
	import extremefx.modules.css.XTextFormat;
	import extremefx.ui.styles.UIStates;
	import extremefx.ui.styles.UIStyle;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;	

	/**
	 * @author Marcelo Volmaro
	 */
	public class Label extends UIComponent {
		private var _text:String;
		private var _measuredHeight:uint;
		private var _tf:TextField;
		private var _bbox:Sprite;
		private var _icon:Icon;
//		private var _actualStyle:XTextFormat;
		private var _actualStyle:UIStyle;
		private var _actualTextStyle:XTextFormat;

		public function Label(pText:String = "", pParameters:UIParameters = null) { 
			super();
			initStyle("Label", pParameters);
			
			var bbox:Sprite = _bbox = new Sprite(),
			tf:TextField = _tf = new TextField();
			
			if (pParameters._icon){
				_icon = pParameters._icon;
				_bbox.addChild(_icon.shape);
			}

			tabEnabled(false);
			
			tf.autoSize = TextFieldAutoSize.NONE;
			tf.selectable = false;
			tf.type = TextFieldType.DYNAMIC;
			tf.condenseWhite = true;
//			tf.border = true;
			
			setState(UIStates.NORMAL);

			_actualStyle.textFormat.applyToTextfield(tf);
			bbox.addChild(tf);
			_visualUI.addChild(bbox);
			text = pText;
		}
		
		public function setState(pState:uint):void {
			_actualStyle = _style.getPseudoStyle(pState);
			(_actualTextStyle = _actualStyle.textFormat).applyToTextfield(_tf);
			invalidate();
		}

		public function get text():String {
			return _text;
		}

		public function set text(pText:String):void {
			var tf:TextField = _tf;
			tf.autoSize = TextFieldAutoSize.LEFT;
			tf.height = 1;
			_text = tf.htmlText = _getText(pText);
			tf.getCharBoundaries(0);//forces to re-compute textfield bounding box
			_measuredHeight = tf.textHeight;
			var h:uint = tf.height;
			tf.autoSize = TextFieldAutoSize.NONE;// prevents "link jumping"
			tf.getCharBoundaries(0);
			tf.height = h + int(tf.getTextFormat().leading) + 1; // adding extra height will prevent "vertical scroll on text select" bug 
			invalidate();
		}

		public function get wordWrap():Boolean { 
			return _tf.wordWrap; 
		}

		public function set wordWrap(pValue:Boolean):void { 
			_tf.wordWrap = pValue;
			text = _text;
		}

		public function get multiline():Boolean { 
			return _tf.multiline; 
		} 

		public function set multiline(pValue:Boolean):void { 
			_tf.multiline = pValue;
			text = _text;
		}

		override protected function _draw():void {
			var tf:TextField = _tf;
			var tfAddX:int, tfAddY:int, tfMaxWidth:int, tfMaxHeight:int;
			
			tfAddX = tfAddY = 0;
			tfMaxWidth = _width;
			tfMaxHeight = _height;
			
			if (tfMaxWidth < 4 || tfMaxHeight < 4) return;
			//don't do anything is size was not provided
			var icon:Icon = _icon;
			
			var vAlign:uint, hAlign:uint;			
			tf.x = tf.y = 0;
			var offsetX:int = _x, offsetY:int = _y;
	
			if (icon) {
				//has icon? need to know to make space to fit the icon...
				vAlign = icon.align & 7;
				//111b
				hAlign = icon.align & 56;
				// 111000b
				var iconShape:DisplayObject = icon.shape;
				
				tfAddX = icon.padding.left + icon.padding.right + iconShape.width;
				tfAddY = icon.padding.top + icon.padding.bottom + iconShape.height;
				
				iconShape.x = iconShape.y = 0;
				
				switch (hAlign) {
					case UIAlign.RIGHT:
						tfMaxWidth -= tfAddX;
						iconShape.x = tfMaxWidth + icon.padding.left;
						break;
					
					case UIAlign.CENTER:
						if (tfAddX < tfMaxWidth) {
							iconShape.x = int((tfMaxWidth - tfAddX) / 2);
						} else {
							tf.x = int((tfAddX - tfMaxWidth) / 2);
						}
						
						break;
					
					default:
						iconShape.x = icon.padding.left;
						tfMaxWidth -= tfAddX;
						tf.x = tfAddX;
				}
				
				switch (vAlign) {
					case UIAlign.TOP:
						tf.y = tfAddY;
						iconShape.y = icon.padding.top; 
						break;
					
					case UIAlign.BOTTOM:
						iconShape.y = tf.height + icon.padding.top; 
						break;
					
					default:
						var th:int = _measuredHeight;
						var descent:int = tf.getLineMetrics(_tf.bottomScrollV - 1).descent;
						
						//icon height < text height
						if (tfAddY < th) {
							iconShape.y = int((th - tfAddY) / 2) + descent;
							
						} else {
							tf.y = int((tfAddY - th) / 2) - descent;
						}
				}
			}
			
			tf.width = tfMaxWidth;
			var diff:int = _bbox.height - tfMaxHeight;
			
			if (0 < diff) {
				tf.height -= diff;
				 
				if (icon && vAlign & UIAlign.BOTTOM) {
					iconShape.y -= diff;
				}
				
			} else {
				vAlign = UIAlign.convert(_actualTextStyle.align, _actualTextStyle.vAlign) & 7;
				//	111b
				//	diff = tfMaxHeight - _bbox.height;
				switch (vAlign) {
					case UIAlign.TOP:
						break;
					
					case UIAlign.BOTTOM:
						offsetY -= diff;
						break;
					
					default:
						offsetY -= int(diff / 2);
				}
			}
			
			tf.filters = _actualTextStyle.filters;
			
//			_bbox.x = _actualStyle.offset.x;
//			_bbox.y = _actualStyle.offset.y;
			_bbox.x = _actualStyle.position.left;
			_bbox.y = _actualStyle.position.top;
			_visualUI.x = offsetX;
			_visualUI.y = offsetY;
		}

		override public function get preferredSize():Size {
			return _calcMinSize(true);
		}

		override public function get minimumSize():Size {
			return _calcMinSize(false);
		}
		
//		public function set color(pColor:Color):void{
//			_color = pColor;
//			_tf.textColor = pColor.toRgb();
//			_tf.alpha = pColor.alpha/255;
//		}
//		
//		public function get color():Color{
//			return _color;
//		}

		/**
		 * si el texto es single line o no word wrap, preferred size devuelve el espacio necesario
		 * para que entre todo el texto + el ícono (si tiene) + padding.
		 * 
		 * Si el texto es multi-line y word wrap, devuelve:
		 * a) si el ancho es < 580px o 60-70 chars, ese ancho y el alto correspondiente.
		 * b) si el ancho es > y getMin, el ancho ajustado a min(580px, 60-70 chars) y el alto correspondiente.
		 * c) si el ancho es > y getPref, el ancho ajustado a max(580px, 60-70 chars) y el alto correspondiente.
		 */
		private function _calcMinSize(pPref:Boolean):Size {
			var tf:TextField = _tf;
			var tfWidth:uint, tfHeight:uint;
			
			var oldW:uint = tf.width;
			var oldH:uint = tf.height;
			
			var r:Rectangle = new Rectangle();
			var r1:Rectangle;
			var chars:int = tf.length;
			
			if (chars > 5) chars = 5;
			
			while (chars--) {
				r1 = tf.getCharBoundaries(chars);
				if (r1) r = r.union(r1);//find biggest char in one line... no need to be exact..
			}
			
			tf.width = r.width; //start width = 1 char aprox...
			tf.height = r.height;//same height...
			
//			trace("text:"+tf.text);
//			trace("starting tf width:"+tf.width+", height:"+tf.height);

			if (tf.wordWrap) {
				var maxCharsWidth:uint = r.width * 64;//good readability: 64 chars per line...
				var maxWidth:uint = pPref ? Math.max(580, maxCharsWidth) : Math.min(580, maxCharsWidth);;
				
				if (tf.multiline){
					while (tf.maxScrollH > 0 && tf.width < maxWidth) tf.width += 4;
					
				} else {//if not multiline, try to have a textfield of ratio 4:3 if width < 580px|64chars
					while (tf.width < maxWidth && (tf.width / tf.height) < 1.333) tf.width += 4;
				}
				
			} else {
//				trace("no wordwrap");
				while (tf.maxScrollH > 0) {
					tf.width += 4;//4 pixels increments... just to be sure italics are covered.
//					trace("calc scroll for width:"+tf.width+" is:"+tf.maxScrollH);
				}
			}

//			buggy text field... maxScrollV does not updated correctly after changing text height...			
//			while (tf.maxScrollV > 1) {
//				tf.height += 4;//unless using a very small font, 4 is a good number...
//				trace("calc scroll for height:"+tf.height+" is:"+tf.maxScrollV);
//			}

			tfWidth = tf.width;
			tf.autoSize = TextFieldAutoSize.LEFT;
			tf.width = tfWidth; 
			tf.htmlText = _text;
			
			tfHeight = tf.height;
			
//			trace("calculated text field size. width:"+tfWidth+", height:"+tfHeight);
			
			tf.autoSize = TextFieldAutoSize.NONE;
			
			tf.width = oldW;//restore text size...
			tf.height = oldH;
			
			var icon:Icon = _icon;
			
			var vAlign:uint, hAlign:uint;			
			
			if (icon) {
				vAlign = icon.align & 7;
				hAlign = icon.align & 56;
				var iconShape:DisplayObject = icon.shape;
				
//				trace("vAlign:"+vAlign+", hAlign:"+hAlign);
				
				if (hAlign != UIAlign.CENTER) {
					//if not center, I need hspace for the icon...
					tfWidth += icon.padding.left + icon.padding.right + iconShape.width;
				}
				
				if (vAlign == UIAlign.TOP || vAlign == UIAlign.BOTTOM) {
					//if not middle, I need vspace for the icon...
					tfHeight += icon.padding.top + icon.padding.bottom + iconShape.height;
				}
			}
			
			//Not sure... removed from here... will be handled on each component
//			tfWidth += _style.padding.left + _style.padding.right; 
//			tfHeight += _style.padding.top + _style.padding.bottom;
			
			return new Size(tfWidth, tfHeight);
		}
	}
}
